// -------------------------------
// Color Selection Button
// Version 1.1
// -------------------------------
// Author: Thomas Ascher
// eMail: thomasascher@hotmail.com
// -------------------------------

using System ;
using System.Drawing ;
using System.ComponentModel ;
using System.Windows.Forms ;

namespace ColorButton
{
public class ColorButton : System.Windows.Forms.Button
{
    private System.ComponentModel.Container components = null ;

    private Color buttonColor = Color.Transparent ;
    private string autoButton = "Automatic" ;
    private string moreButton = "More Colors..." ;
    private bool buttonPushed = false ;
    private bool panelVisible = false ;

    public event EventHandler Changed ;

    public Color Color
    {
        get { return buttonColor ; }
        set { buttonColor = value ;
        Invalidate();
    }
    }

    public string Automatic
    {
        get { return autoButton ; }
        set { autoButton = value ; }
    }

    public string MoreColors
    {
        get { return moreButton ; }
        set { moreButton = value ; }
    }

    protected virtual void OnChanged( EventArgs e )
    {
        if( Changed != null )
            Changed( this, e ) ;
    }

    public ColorButton()
    {
        InitializeComponent() ;
    }

    protected override void Dispose( bool disposing )
    {
        if( disposing )
        {
            if( components != null )
                components.Dispose() ;
        }

        base.Dispose( disposing ) ;
    }

    #region Vom Komponenten-Designer generierter Code
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container() ;
    }
    #endregion

    protected override void OnPaint( PaintEventArgs e )
    {
        base.OnPaint( e ) ;

        int offset = 0 ;

        if( panelVisible || ( buttonPushed &&
            RectangleToScreen( ClientRectangle ).Contains( Cursor.Position ) ) )
        {
            ControlPaint.DrawButton( e.Graphics, e.ClipRectangle, ButtonState.Pushed ) ;
            offset = 1 ;
        }

        Rectangle rc = new Rectangle( e.ClipRectangle.Left + 5 + offset,
                                      e.ClipRectangle.Top + 5 + offset,
                                      e.ClipRectangle.Width - 24,
                                      e.ClipRectangle.Height - 11 ) ;
        Pen darkPen = new Pen( SystemColors.ControlDark ) ;

        if( Enabled )
        {
            e.Graphics.FillRectangle( new SolidBrush( buttonColor ), rc ) ;
            e.Graphics.DrawRectangle( darkPen, rc ) ;
        }

        e.Graphics.DrawLine( darkPen, rc.Right + 4, rc.Top, rc.Right + 4, rc.Bottom ) ;
        e.Graphics.DrawLine( new Pen( SystemColors.ControlLightLight ),
                             rc.Right + 5, rc.Top, rc.Right + 5, rc.Bottom ) ;

        Pen textPen = new Pen( Enabled ? SystemColors.ControlText : SystemColors.GrayText ) ;
        Point pt = new Point( rc.Right, ( e.ClipRectangle.Height + offset ) / 2 ) ;

        e.Graphics.DrawLine( textPen, pt.X +  9, pt.Y - 1, pt.X + 13, pt.Y - 1 ) ;
        e.Graphics.DrawLine( textPen, pt.X + 10, pt.Y,     pt.X + 12, pt.Y     ) ;
        e.Graphics.DrawLine( textPen, pt.X + 11, pt.Y,     pt.X + 11, pt.Y + 1 ) ;
    }

    protected override void OnMouseDown( MouseEventArgs e )
    {
        buttonPushed = true ;
        base.OnMouseDown( e ) ;
    }

    protected override void OnMouseUp( MouseEventArgs e )
    {
        buttonPushed = false ;
        base.OnMouseUp( e ) ;
    }

    protected override void OnClick( EventArgs e )
    {
        panelVisible = true ;
        Refresh() ;

        Point pt = Parent.PointToScreen( new Point( Left, Bottom ) ) ;

        ColorPanel panel = new ColorPanel( pt, this ) ;
        panel.Show() ;
    }

    protected class ColorPanel : System.Windows.Forms.Form
    {
        private ColorButton colorButton ;
        private int colorIndex = -1 ;
        // ADDED: Ignazio Di Napoli - neclepsio@hotmail.com
        private int keyboardIndex = -50 ;
        // END ADDED

        private Color[] colorList = new Color[40]
        {
            Color.FromArgb( 0x00, 0x00, 0x00 ), Color.FromArgb( 0x99, 0x33, 0x00 ),
            Color.FromArgb( 0x33, 0x33, 0x00 ), Color.FromArgb( 0x00, 0x33, 0x00 ),
            Color.FromArgb( 0x00, 0x33, 0x66 ), Color.FromArgb( 0x00, 0x00, 0x80 ),
            Color.FromArgb( 0x33, 0x33, 0x99 ), Color.FromArgb( 0x33, 0x33, 0x33 ),

            Color.FromArgb( 0x80, 0x00, 0x00 ), Color.FromArgb( 0xFF, 0x66, 0x00 ),
            Color.FromArgb( 0x80, 0x80, 0x00 ), Color.FromArgb( 0x00, 0x80, 0x00 ),
            Color.FromArgb( 0x00, 0x80, 0x80 ), Color.FromArgb( 0x00, 0x00, 0xFF ),
            Color.FromArgb( 0x66, 0x66, 0x99 ), Color.FromArgb( 0x80, 0x80, 0x80 ),

            Color.FromArgb( 0xFF, 0x00, 0x00 ), Color.FromArgb( 0xFF, 0x99, 0x00 ),
            Color.FromArgb( 0x99, 0xCC, 0x00 ), Color.FromArgb( 0x33, 0x99, 0x66 ),
            Color.FromArgb( 0x33, 0xCC, 0xCC ), Color.FromArgb( 0x33, 0x66, 0xFF ),
            Color.FromArgb( 0x80, 0x00, 0x80 ), Color.FromArgb( 0x99, 0x99, 0x99 ),

            Color.FromArgb( 0xFF, 0x00, 0xFF ), Color.FromArgb( 0xFF, 0xCC, 0x00 ),
            Color.FromArgb( 0xFF, 0xFF, 0x00 ), Color.FromArgb( 0x00, 0xFF, 0x00 ),
            Color.FromArgb( 0x00, 0xFF, 0xFF ), Color.FromArgb( 0x00, 0xCC, 0xFF ),
            Color.FromArgb( 0x99, 0x33, 0x66 ), Color.FromArgb( 0xC0, 0xC0, 0xC0 ),

            Color.FromArgb( 0xFF, 0x99, 0xCC ), Color.FromArgb( 0xFF, 0xCC, 0x99 ),
            Color.FromArgb( 0xFF, 0xFF, 0x99 ), Color.FromArgb( 0xCC, 0xFF, 0xCC ),
            Color.FromArgb( 0xCC, 0xFF, 0xFF ), Color.FromArgb( 0x99, 0xCC, 0xFF ),
            Color.FromArgb( 0xCC, 0x99, 0xFF ), Color.FromArgb( 0xFF, 0xFF, 0xFF )
        } ;

        public ColorPanel( Point pt, ColorButton button )
        {
            colorButton = button ;

            FormBorderStyle = FormBorderStyle.FixedDialog ;
            MinimizeBox = false ;
            MaximizeBox = false ;
            ControlBox = false ;
            ShowInTaskbar = false ;
            TopMost = true ;

            SetStyle( ControlStyles.DoubleBuffer, true ) ;
            SetStyle( ControlStyles.UserPaint, true ) ;
            SetStyle( ControlStyles.AllPaintingInWmPaint, true ) ;

            Width = 156 ;
            Height = 100 ;

            if( colorButton.autoButton != "" )
                Height += 23 ;
            if( colorButton.moreButton != "" )
                Height += 23 ;

            CenterToScreen() ;
            Location = pt ;

            Capture = true ;
        }

        protected override void OnClosed( EventArgs e )
        {
            base.OnClosed( e ) ;

            colorButton.panelVisible = false ;
            colorButton.Refresh() ;
        }

        protected override void OnPaint( PaintEventArgs e )
        {
            base.OnPaint( e ) ;

            Pen darkPen = new Pen( SystemColors.ControlDark ) ;
            Pen lightPen = new Pen( SystemColors.ControlLightLight ) ;
            SolidBrush lightBrush = new SolidBrush( SystemColors.ControlLightLight ) ;
            bool selected = false ;
            int x = 6, y = 5 ;

            if( colorButton.autoButton != "" )
            {
                selected = colorButton.Color == Color.Transparent ;
                DrawButton( e, x, y, colorButton.autoButton, 100, selected ) ;
                y += 23 ;
            }

            for( int i = 0 ; i < 40 ; i++ )
            {
                if( colorButton.Color.ToArgb() == colorList[i].ToArgb() )
                    selected = true ;

                if( colorIndex == i )
                {
                    e.Graphics.DrawRectangle( lightPen, x - 3, y - 3, 17, 17 ) ;
                    e.Graphics.DrawLine( darkPen, x - 2, y + 14, x + 14, y + 14 ) ;
                    e.Graphics.DrawLine( darkPen, x + 14, y - 2, x + 14, y + 14 ) ;
                }
                else if( colorButton.Color.ToArgb() == colorList[i].ToArgb() )
                {
                    // ADDED: Ignazio Di Napoli - neclepsio@hotmail.com
                    if( keyboardIndex == -50 )
                        keyboardIndex = i ;
                    // END ADDED

                    e.Graphics.FillRectangle( lightBrush, x - 3, y - 3, 18, 18 ) ;
                    e.Graphics.DrawLine( darkPen, x - 3, y - 3, x + 13, y - 3 ) ;
                    e.Graphics.DrawLine( darkPen, x - 3, y - 3, x - 3, y + 13 ) ;
                }

                e.Graphics.FillRectangle( new SolidBrush( colorList[i] ), x, y, 11, 11 ) ;
                e.Graphics.DrawRectangle( darkPen, x, y, 11, 11 ) ;

                if( ( i + 1 ) % 8 == 0 )
                {
                    x = 6 ;
                    y += 18 ;
                }
                else
                    x += 18 ;
            }

            if( colorButton.moreButton != "" )
                DrawButton( e, x, y, colorButton.moreButton, 101, ! selected ) ;
        }

        // ADDED: Ignazio Di Napoli - neclepsio@hotmail.com
        protected override void OnKeyDown( KeyEventArgs e )
        {
            if( e.KeyCode == Keys.Escape )
                Close() ;
            else if( e.KeyCode == Keys.Left )
                MoveIndex( -1 ) ;
            else if( e.KeyCode == Keys.Up )
                MoveIndex( -8 ) ;
            else if( e.KeyCode == Keys.Down )
                MoveIndex( +8 ) ;
            else if( e.KeyCode == Keys.Right )
                MoveIndex( +1 ) ;
            else if( e.KeyCode == Keys.Enter ||
                     e.KeyCode == Keys.Space )
                OnClick( EventArgs.Empty ) ;
            else
                base.OnKeyDown( e ) ;
        }

        private void MoveIndex( int delta )
        {
            int lbound = ( colorButton.autoButton != "" ? -8 : 0 ) ;
            int ubound = 39 + ( colorButton.moreButton != "" ? 8 : 0 ) ;
            int d = ubound - lbound + 1 ;

            if( delta == -1 && keyboardIndex < 0 )
                keyboardIndex = ubound ;
            else if( delta == 1 && keyboardIndex > 39 )
                keyboardIndex = lbound ;
            else if( delta == 1 && keyboardIndex < 0 )
                keyboardIndex = 0 ;
            else if( delta == -1 && keyboardIndex > 39 )
                keyboardIndex = 39 ;
            else
                keyboardIndex += delta ;

            if( keyboardIndex < lbound )
                keyboardIndex += d ;
            if( keyboardIndex > ubound )
                keyboardIndex -= d ;

            if( keyboardIndex < 0 )
                colorIndex = 100 ;
            else if( keyboardIndex > 39 )
                colorIndex = 101 ;
            else
                colorIndex = keyboardIndex ;

            Refresh() ;
        }
        // END ADDED

        protected override void OnMouseDown( MouseEventArgs e )
        {
            if( RectangleToScreen( ClientRectangle ).Contains( Cursor.Position ) )
                base.OnMouseDown( e ) ;
            else
                Close() ;
        }

        protected override void OnMouseMove( MouseEventArgs e )
        {
            base.OnMouseMove( e ) ;

            if( RectangleToScreen( ClientRectangle ).Contains( Cursor.Position ) )
            {
                Point pt = PointToClient( Cursor.Position ) ;
                int x = 6, y = 5 ;

                if( colorButton.autoButton != "" )
                {
                    if( SetColorIndex( new Rectangle( x - 3, y - 3, 143, 22 ), pt, 100 ) )
                        return ;

                    y += 23 ;
                }

                for( int i = 0 ; i < 40 ; i++ )
                {
                    if( SetColorIndex( new Rectangle( x - 3, y - 3, 17, 17 ), pt, i ) )
                        return ;

                    if( ( i + 1 ) % 8 == 0 )
                    {
                        x = 6 ;
                        y += 18 ;
                    }
                    else
                        x += 18 ;
                }

                if( colorButton.moreButton != "" )
                {
                    if( SetColorIndex( new Rectangle( x - 3, y - 3, 143, 22 ), pt, 101 ) )
                        return ;
                }
            }

            if( colorIndex != -1 )
            {
                colorIndex = -1 ;
                Invalidate() ;
            }
        }

        protected override void OnClick( EventArgs e )
        {
            if( colorIndex < 0 )
                return ;

            if( colorIndex < 40 )
                colorButton.Color = colorList[colorIndex] ;
            else if( colorIndex == 100 )
                colorButton.Color = Color.Transparent ;
            else
            {
                ColorDialog dlg = new ColorDialog() ;
                dlg.Color = colorButton.Color ;
                dlg.FullOpen = true ;

                if( dlg.ShowDialog( this ) != DialogResult.OK )
                {
                    Close() ;
                    return ;
                }

                colorButton.Color = dlg.Color ;
            }

            Close() ;
            colorButton.OnChanged( EventArgs.Empty ) ;
        }

        protected void DrawButton( PaintEventArgs e, int x, int y, string text,
                                   int index, bool selected )
        {
            Pen darkPen = new Pen( SystemColors.ControlDark ) ;
            Pen lightPen = new Pen( SystemColors.ControlLightLight ) ;
            SolidBrush lightBrush = new SolidBrush( SystemColors.ControlLightLight ) ;

            if( colorIndex == index )
            {
                e.Graphics.DrawRectangle( lightPen, x - 3, y - 3, 143, 22 ) ;
                e.Graphics.DrawLine( darkPen, x - 2, y + 19, x + 140, y + 19 ) ;
                e.Graphics.DrawLine( darkPen, x + 140, y - 2, x + 140, y + 19 ) ;
            }
            else if( selected )
            {
                e.Graphics.FillRectangle( lightBrush, x - 3, y - 3, 144, 23 ) ;
                e.Graphics.DrawLine( darkPen, x - 3, y - 3, x + 139, y - 3 ) ;
                e.Graphics.DrawLine( darkPen, x - 3, y - 3, x - 3, y + 18 ) ;
            }

            Rectangle rc = new Rectangle( x, y, 137, 16 ) ;
            SolidBrush textBrush = new SolidBrush( SystemColors.ControlText ) ;

            StringFormat textFormat = new StringFormat() ;
            textFormat.Alignment = StringAlignment.Center ;
            textFormat.LineAlignment = StringAlignment.Center ;

            e.Graphics.DrawRectangle( darkPen, rc ) ;
            e.Graphics.DrawString( text, colorButton.Font, textBrush, rc, textFormat ) ;
        }

        protected bool SetColorIndex( Rectangle rc, Point pt, int index )
        {
            if( rc.Contains( pt ) )
            {
                if( colorIndex != index )
                {
                    colorIndex = index ;
                    Invalidate() ;
                }

                return true ;
            }

            return false ;
        }
    }
}
}
